package com.zysdev.opengldouyin1demo.filter

import android.graphics.SurfaceTexture
import android.opengl.EGL14
import android.opengl.GLSurfaceView
import android.os.Environment
import androidx.camera.core.Preview
import androidx.lifecycle.LifecycleOwner
import com.zysdev.opengldouyin1demo.R
import com.zysdev.opengldouyin1demo.filter.addFilter.SoulFilter
import com.zysdev.opengldouyin1demo.filter.addFilter.SplitScreenFilter
import java.io.File
import java.io.IOException
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class CameraRender : GLSurfaceView.Renderer, Preview.OnPreviewOutputUpdateListener,
    SurfaceTexture.OnFrameAvailableListener {

    private var cameraView: CameraView? = null

    private var surfaceTexture: SurfaceTexture? = null
    private val textures: IntArray = IntArray(1)
    private var cameraFilter: CameraFilter? = null

    //渲染到屏幕上
    private var showScreenFilter: ShowScreenFilter? = null

    private var split2ScreenFilter: SplitScreenFilter? = null
    private var split4ScreenFilter: SplitScreenFilter? = null
    private var soulFilter: SoulFilter? = null

    private var mtx = FloatArray(16)

    private var mediaRecorder: MediaRecorder? = null

    constructor(cameraView: CameraView) {
        this.cameraView = cameraView
        val lifecycleOwner = cameraView.context as LifecycleOwner
        //打开摄像头
        CameraHelper(lifecycleOwner, this)

    }

    // 打开摄像头后，摄像头预览到的数据通过接口回调到这里
    override fun onUpdated(output: Preview.PreviewOutput?) {
        //获取到摄像头的预览数据，数据在surfaceTexture里
        surfaceTexture = output?.surfaceTexture

    }

    override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
//      让SurfaceTexture与Gpu共享一个数据源0-31
        //绑定摄像头和GPU，此时会在GPU创建一个内存
        surfaceTexture?.attachToGLContext(textures[0])

        //当有数据过来时的回调
        surfaceTexture?.setOnFrameAvailableListener(this)
        val context = cameraView!!.context

        cameraFilter = CameraFilter(context)
        soulFilter = SoulFilter(context)
        showScreenFilter = ShowScreenFilter(context)
        split2ScreenFilter = SplitScreenFilter(context, R.raw.base_vert, R.raw.split2_frag)
        split4ScreenFilter = SplitScreenFilter(context, R.raw.base_vert, R.raw.split4_frag)
//        split3ScreenFilter = ShowScreenFilter(context)

        val file = File(Environment.getExternalStorageDirectory(), "opengl_filter_output.mp4")
        if (file.exists()) {
            file.delete()
        }

        val path = file.absolutePath
        mediaRecorder = MediaRecorder(context, path, EGL14.eglGetCurrentContext(), 480, 640)
    }

    override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {
        showScreenFilter?.setSize(width, height)
        cameraFilter?.setSize(width, height)
        split2ScreenFilter?.setSize(width, height)
        split4ScreenFilter?.setSize(width, height)
        soulFilter?.setSize(width, height)
    }

    //这里的线程是GLThread
    //当GLSurfaceView重新渲染时requestRender()，会回调到这里
    override fun onDrawFrame(p0: GL10?) {
        //        更新数据
        surfaceTexture?.updateTexImage()
        //将图像的矩阵信息保存到mtx中
        surfaceTexture?.getTransformMatrix(mtx)

        cameraFilter?.setTransformMatrix(mtx)

        //1、将摄像头数据传到FBO中
        //传入一个原纹理图层id，cameraFilter返回的是FBO的纹理图层ID，可以对FBO的纹理图层进行操作
        //fbo里此时是摄像头的画面数据，摄像头被FBO拦截了，不会输出到屏幕，屏幕没画面
        var fboTextureId: Int = cameraFilter?.onDraw(textures[0])!!
//        Log.e("---", "----fboTextureId=$fboTextureId")

        //2、处理FBO数据，加特效

        //(1)分两屏
//        fboTextureId = split2ScreenFilter?.onDraw(fboTextureId)!!
        //(2)分四屏
        fboTextureId = split4ScreenFilter?.onDraw(fboTextureId)!!
//        (3)灵魂出窍
        fboTextureId = soulFilter!!.onDraw(fboTextureId)

        //3、将处理完的FBO纹理图层渲染到屏幕
        fboTextureId = showScreenFilter!!.onDraw(fboTextureId)


        //4、将数据录制到本地文件或发送出去
        //注意如果要取FBO数据，需要创建EGL环境（opengl线程），才能调用Opengl函数
        mediaRecorder?.fireFrame(fboTextureId,surfaceTexture!!.timestamp)

    }


    //SurfaceTexture里有数据时
    override fun onFrameAvailable(p0: SurfaceTexture?) {
        //让cameraView手动刷新
        cameraView?.requestRender()
    }


    fun startRecord(speed: Float) {
        try {
            mediaRecorder?.start(speed)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    fun stopRecord() {
        mediaRecorder?.stop()
    }
}